package com.netty.chat.server;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.netty.chat.entity.User;
import com.netty.chat.message.MessageRequest;
import com.netty.chat.message.MessageResponse;
import com.netty.chat.constant.MessageType;
import com.netty.chat.service.UserService;
import com.netty.chat.vo.GroupChat;
import com.netty.chat.vo.UserInfo;
import com.netty.chat.vo.UserSocketChannel;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.channel.group.ChannelGroup;
import io.netty.channel.group.DefaultChannelGroup;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import io.netty.util.concurrent.GlobalEventExecutor;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

import static com.netty.chat.constant.ChatConstant.GLOBLE_CHAT_RECORD;

//TextWebSocketFrame 在 netty 中是用于webSocket专门处理文本对象,frame是消息的载体.
@Component
@ChannelHandler.Sharable
public class ChatHandler extends SimpleChannelInboundHandler<TextWebSocketFrame> {
    //用于记录和管理所有客户端的Channel，key为用户唯一标识id
    public static Map<Integer, UserSocketChannel> userChannel = new ConcurrentHashMap<>();
    //管理群聊的channel，key为群员的id以-为分隔符组成字符串
    public static Map<String, GroupChat> groupChannel = new ConcurrentHashMap<>();
    /**
     * 聊天记录的存储,
     * 私聊key为双方用户的id的拼接，按大小递减拼接id-id，
     * 群聊为群聊标识符
     */
    public static Map<String, List<MessageResponse>> chatRecord = new ConcurrentHashMap<>();

    public static ChannelGroup globleChannelGroup = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);

    @Autowired
    UserService userService;
    private ObjectMapper objectMapper = new ObjectMapper();

    //当接收到客户端发过来的消息就会触发此回调
    @Override
    protected void channelRead0(ChannelHandlerContext channelHandlerContext, TextWebSocketFrame textWebSocketFrame) throws Exception {
        String content = textWebSocketFrame.text();
        MessageRequest message = objectMapper.readValue(content, MessageRequest.class);
        System.out.println("接收到的数据: " + content);
        analyzeMessage(message, channelHandlerContext);
    }
    /**
     * 在容器填充完该bean的属性后，调用此函数进行进一步初始化逻辑
     * 初始化私聊的聊天记录
     */
    @PostConstruct
    public void initializeChatRecords() {
        //个人聊天记录
        List<User> users = userService.queryList(null);
        for (int i = 0; i < users.size(); i++) {
            User user1 = users.get(i);
            for (int j = i + 1; j < users.size(); j++) {
                User user2 = users.get(j);
                String key = user1.getId() + "-" + user2.getId();
                chatRecord.put(key, new ArrayList<>());
            }
        }
        //广播聊天记录初始
        chatRecord.put(GLOBLE_CHAT_RECORD,new ArrayList<>());
    }

    public void analyzeMessage(MessageRequest messageRequest, ChannelHandlerContext context) throws JsonProcessingException {
        String channelId;
        String data;
        Channel channel;
        UserSocketChannel userSocketChannel;
        MessageResponse message = new MessageResponse();
        BeanUtils.copyProperties(messageRequest, message);
        User send = userService.queryById(messageRequest.getSend());//发送者的信息
        message.setSendName(send.getUsername());
        switch (message.getMessageType()) {
            case MessageType.BIND_CHANNEL:
                userSocketChannel = new UserSocketChannel();
                userSocketChannel.setChannel(context.channel());
                User user = userService.queryById(message.getSend());
                UserInfo userInfo = new UserInfo();
                BeanUtils.copyProperties(user, userInfo);
                userSocketChannel.setUserInfo(userInfo);
                //如果是未登录状态，广播通知该用户上线了
                if (!userChannel.containsKey(messageRequest.getSend())){
                    data = objectMapper.writeValueAsString(message);
                    globleChannelGroup.writeAndFlush(new TextWebSocketFrame(data));
                    //记录聊天记录
                    chatRecord.get(GLOBLE_CHAT_RECORD).add(message);
                }
                userChannel.put(message.getSend(), userSocketChannel);
                break;
            case MessageType.SEND_TO_USER:
                channelId = message.getChannelId();
                userSocketChannel = userChannel.get(Integer.valueOf(channelId));
                if (userSocketChannel != null) {
                    channel = userSocketChannel.getChannel();
                    if (channel.isActive()){
                        //确定对方在线才发送，不然直接记录到聊天记录即可
                        data = objectMapper.writeValueAsString(message);
                        channel.writeAndFlush(new TextWebSocketFrame(data));
                    }
                }
                //记录聊天记录
                String key = getKey(message.getSend(), message.getReceive());
                List<MessageResponse> records = chatRecord.get(key);
                records.add(message);
                break;
            case MessageType.SEND_TO_GROUP:
                channelId = message.getChannelId();
                GroupChat groupChat = groupChannel.get(channelId);
                Set<UserInfo> userInfos = groupChat.getMembers();
                data = objectMapper.writeValueAsString(message);
                for (UserInfo member : userInfos) {
                    if (!member.getId().equals(message.getSend())) {
                        userSocketChannel = userChannel.get(member.getId());
                        if (userSocketChannel != null) {
                            channel = userSocketChannel.getChannel();
                            channel.writeAndFlush(new TextWebSocketFrame(data));
                        }
                    }
                }
                //记录聊天记录
                List<MessageResponse> groupRecords = chatRecord.computeIfAbsent(channelId, k -> new ArrayList<>());
                groupRecords.add(message);
                break;
            case MessageType.SEND_TO_GLOBLE:
                data = objectMapper.writeValueAsString(message);
                for (Channel channel1 : globleChannelGroup) {
                    if (channel1!=context.channel()){
                        channel1.writeAndFlush(new TextWebSocketFrame(data));
                    }
                }
                //记录聊天记录
                chatRecord.get(GLOBLE_CHAT_RECORD).add(message);
                break;
        }
    }

    public String getKey(Integer id1, Integer id2) {
        String key;
        if (id1 > id2) {
            key = id2 + "-" + id1;
        } else {
            key = id1 + "-" + id2;
        }
        return key;
    }

    //当有新的客户端连接服务器之后,就会自动调用这个方法
    @Override
    public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
        globleChannelGroup.add(ctx.channel());
    }

}
